package com.cxmx.escort.service.Impl;

import cn.hutool.core.util.HexUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cxmx.escort.base.MD5Utils;
import com.cxmx.escort.base.ResponseFormat;
import com.cxmx.escort.baseEnum.VariableEnum;
import com.cxmx.escort.common.redis.RedisUtils;
import com.cxmx.escort.config.sdk.NBIoTAuthService;
import com.cxmx.escort.config.sdk.NBOceanConnectService;
import com.cxmx.escort.entity.Bed;
import com.cxmx.escort.entity.BedOrder;
import com.cxmx.escort.entity.Region;
import com.cxmx.escort.mapper.BedMapper;
import com.cxmx.escort.service.IBedOrderService;
import com.cxmx.escort.service.IBedService;
import com.cxmx.escort.service.IRegionService;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * <p>
 * 充值表 服务实现类
 * </p>
 *
 * @author 陈云轩
 * @since 2019-10-21
 */
@Service
@Log4j
public class BedServiceImpl extends ServiceImpl<BedMapper, Bed> implements IBedService {

    @Autowired
    NBOceanConnectService nbOceanConnectService;
    @Autowired
    IBedOrderService bedOrderService;
    @Autowired
    WxPayService wxService;
    @Autowired
    IRegionService regionService;

    @Autowired
    NBIoTAuthService service;

    @Override
    public  String requestOpenLock(String deviceId, String cmd) {
        saveOrUpdate(cmd);
        //开锁
        String code = HexUtil.decodeHexStr(cmd.substring(0, 30));
        Object type = RedisUtils.get("bed:bed:" + code);
        if (null != type) {
            synchronized (this){
                log.error("start open token");
                service.login();
                log.error("start open lock");
                RedisUtils.set("bed:getOrderUser:" + code, type);
                RedisUtils.del("bed:bed:" + code);
                nbOceanConnectService.unlock(deviceId, cmd);
            }
        }
        log.error("open lock end:");
        return null;
    }

    @Override
    public String requestSynchronous(String deviceId, String cmd) {
        String id = saveOrUpdate(cmd);
        RedisUtils.set("bed:activeStatus:" + id, 1, 60 * 60 * 24);
        return null;
    }

    @Override
    public String requestOpenLockSuccess(String cmd) {
        String id = saveOrUpdate(cmd);
        String code = HexUtil.decodeHexStr(cmd.substring(0, 30));
        if (null == RedisUtils.get("bed:getOrderUser:" + code)) {
            return null;
        }
        //开启了一次锁
        String userId = String.valueOf(RedisUtils.get("bed:getOrderUser:" + code));
        RedisUtils.incr(LocalDateTime.now().format(DateTimeFormatter.ofPattern("YYYYMMdd")) + ":" + userId, 1);
        //插入正在进行的订单
        BedOrder order = new BedOrder();
        order.setBedId(id);
        order.setUserId(userId);
        order.setBedCode(code);

        //设置单价
        QueryWrapper<Bed> qwb = new QueryWrapper<>();
        qwb.eq("bed_code", code);
        Bed bed = this.getOne(qwb);
        if (null != bed) {
            if (null == bed.getHospitalId()) {
                order.setUnitCost(new BigDecimal(0.01));
                ResponseFormat.retParam(70015, null);
            } else {
                Region region = regionService.getById(bed.getHospitalId());
                order.setUnitCost(region.getPrice());
            }
        }

        //设置其他属性
        order.setLockTime(LocalDateTime.now());
        order.setOrderStatus(1);
        order.setPrice(new BigDecimal(0.0));
        order.setPayType(1);
        bedOrderService.save(order);
        RedisUtils.del("bed:getUserId:" + RedisUtils.get("bed:bed:" + code));
        RedisUtils.del("bed:getOrderUser:" + code);
        log.error("open lock success");
        return null;
    }

    @Override
    public String requestCloseLockSuccess(String cmd) {
        String id = saveOrUpdate(cmd);
        QueryWrapper<BedOrder> qw = new QueryWrapper<>();
        qw.eq("bed_id", id);
        qw.eq("order_status", 1);
        BedOrder bedOrder = bedOrderService.getOne(qw);
        if (null == bedOrder) {
            return null;
        }
        bedOrder.setUnlockTime(LocalDateTime.now());
        BigDecimal bigDecimal = new BigDecimal(MD5Utils.getPrice(bedOrder.getLockTime(), bedOrder.getUnlockTime(), bedOrder.getUnitCost().doubleValue(), bedOrder.getUserId()));
        bedOrder.setPrice(bigDecimal);
        String code = HexUtil.decodeHexStr(cmd.substring(0, 30));
        RedisUtils.del("bed:bed:" + code);
        log.error("close lock success");
        double consumePrice = bedOrder.getPrice().doubleValue() * 100;
        int refundFee = VariableEnum.THE_DEPOSIT.getCode() - (int) consumePrice;
        //如果可以承担
        if (refundFee >= 0) {
            bedOrder.setOrderStatus(3);
            double back = (double) refundFee / 100;
            bedOrder.setBackPrice(new BigDecimal(back));
            bedOrder.setUnpaidPrice(new BigDecimal(0));
            String refundId = String.valueOf(RedisUtils.get("bed:getRefundId:" + bedOrder.getUserId()));
            WxPayRefundRequest wxPayUnifiedOrderRequest = new WxPayRefundRequest();
            wxPayUnifiedOrderRequest.setRefundFee(refundFee);
            wxPayUnifiedOrderRequest.setTotalFee(VariableEnum.THE_DEPOSIT.getCode());
            wxPayUnifiedOrderRequest.setRefundDesc("退还预付款");
            wxPayUnifiedOrderRequest.setOutTradeNo(refundId);
            wxPayUnifiedOrderRequest.setNotifyUrl("https://api.bochenkj.cn/pay/notify/refund");
            wxPayUnifiedOrderRequest.setRefundFeeType("CNY");
            wxPayUnifiedOrderRequest.setOutRefundNo(refundId);
            try {
                wxService.refund(wxPayUnifiedOrderRequest);
                RedisUtils.del("bed:getRefundId:" + bedOrder.getUserId());
                RedisUtils.del("bed:getUserId:" + bedOrder.getUserId());
            } catch (WxPayException e) {
                e.printStackTrace();
            }
        } else {
            bedOrder.setBackPrice(new BigDecimal(0));
            bedOrder.setOrderStatus(2);
            bedOrder.setUnpaidPrice(new BigDecimal(-(double) refundFee / 100));
        }

        bedOrderService.updateById(bedOrder);

        return null;
    }

    private String saveOrUpdate(String cmd) {
        String signal = String.valueOf(Integer.parseInt(cmd.substring(42, 44), 16));
        String electricity = String.valueOf(Integer.parseInt(cmd.substring(44, 46), 16));
        String code = HexUtil.decodeHexStr(cmd.substring(0, 30));
        Bed bed = this.baseMapper.selectByCode(code);
        if (null == bed) {
            Bed bedNew = new Bed();
            bedNew.setBedCode(code);
            bedNew.setBedSignal(String.valueOf(Double.valueOf(signal) / 31));
            bedNew.setBedElectricity(electricity);
            bedNew.setSynchronousTime(LocalDateTime.now());
            this.baseMapper.insert(bedNew);
            return bedNew.getId();
        } else {
            bed.setBedSignal(String.valueOf(Double.valueOf(signal) / 31));
            bed.setFaultFlag(1);
            bed.setBedElectricity(electricity);
            bed.setSynchronousTime(LocalDateTime.now());
            this.baseMapper.updateById(bed);
            return bed.getId();
        }
    }
}
